#define _CRT_SECURE_NO_WARNINGS 1

#include "Book.h"
#include "Borrower.h"

DLNode2* BorrowertInit()
{
    DLNode2* pHead = (DLNode2*)malloc(sizeof(DLNode2));
    if (pHead == NULL)
    {
        printf("malloc failed!\n");
        exit(-1);
    }
    pHead->next = pHead;
    pHead->prev = pHead;

    LoadBorrower(pHead); // 从文件中读取借阅者信息函数

    return pHead;
    //这里我们使用 malloc 函数开辟一块空间作为 "哨兵位" pHead ，
    //最后将其进行一个初始化。最后再将 pHead 作为结果返回回去，外面就可以接收到了。
    //这就是返回值的方法，当然这里也可以采用二级指针的方法来完成。
}

void LoadBorrower(DLNode2* pHead)
{
    FILE* pf = fopen("Borrower.dat", "r");
    if (pf == NULL)
    {
        perror("LoadBorrower");
        printf("此时无借阅者信息。\n");
        return;
    }
    else
    {
        printf("此时已有借阅者信息，可输入4查看。\n");
    }

    struct Borrower s = { 0 }; // 存放处
    while (fread(&s, sizeof(Borrower), 1, pf))
    {
        //DListPushBack2();自己一步实现尾插：

        DLNode2* newNode = (DLNode2*)malloc(sizeof(DLNode2));
        if (newNode == NULL)
        {
            printf("malloc failed!\n");
            exit(-1);
        }
        strcpy(newNode->data.book_number, s.book_number);
        strcpy(newNode->data.borrower_number, s.borrower_number);
        strcpy(newNode->data.limit_date, s.limit_date);

        DLNode2* tail = pHead->prev;

        tail->next = newNode;//原尾指向新尾
        newNode->prev = tail;//新尾指回原尾
        pHead->prev = newNode;//哨兵指到新尾
        newNode->next = pHead;//新尾指回哨兵
    }

    fclose(pf);//关闭文件
    pf = NULL;
}

DLNode2* DListFind2(DLNode2* pHead, char* borrower_number)
{
    assert(pHead != NULL);
    DLNode2* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）（和打印一样）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    while (cur != pHead)
    {
        if (strcmp(cur->data.borrower_number, borrower_number) == 0)//根据书证号查找，找到了就返回这个结点
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

void BorrowBook(DLNode* pHead, DLNode2* pHead2) // 借阅
{
    printf("\n<借阅>\n"); 
    printf("请输入您的书证号\n");
    char borrower_number_tmp[20];
    scanf("%s", borrower_number_tmp);

    DLNode2* tmp2 = DListFind2(pHead2, borrower_number_tmp);
    if (tmp2 != NULL)
    {
        printf("您已借过书，不可再借\n\n");
        return;
    }

    printf("请输入借阅的书的书号：");

    char book_number_tmp[20]; // 书号
    scanf("%s", book_number_tmp);
    DLNode* tmp = DListFind(pHead, book_number_tmp);
    if (tmp != NULL)
    {
        if (tmp->data.now_num >= 1)
        {

            DListPushBack2(pHead2, book_number_tmp, borrower_number_tmp);

            tmp->data.now_num -= 1;
            printf("借阅成功！\n\n");
        }
        else
        {
            printf("库存不足！\n\n");
        }
    }
    else
    {
        printf("无此书号图书。\n\n");
    }
}

DLNode2* CreateNewNode2(char* book_number, char* borrower_number)
{
    DLNode2* newNode = (DLNode2*)malloc(sizeof(DLNode2));
    if (newNode == NULL)
    {
        printf("malloc failed!\n");
        exit(-1);
    }

    strcpy(newNode->data.book_number, book_number); // 书号

    strcpy(newNode->data.borrower_number, borrower_number); // 书证号

    printf("请输入归还期限（年月日）：");
    scanf("%s", newNode->data.limit_date);

    newNode->next = NULL;
    newNode->prev = NULL;
    return newNode;
}


void DListPushBack2(DLNode2* pHead, char* book_number, char* borrower_number)
{
    DListInsert2(pHead, book_number, borrower_number);//在pHead的前一个(prev)插入就是尾插
}

void DListInsert2(DLNode2* pos, char* book_number,char* borrower_number)//在pos之前插入
{
    assert(pos != NULL);
    DLNode2* newNode = CreateNewNode2(book_number, borrower_number);
    DLNode2* posPrev = pos->prev;//记录pos前节点
    posPrev->next = newNode;//pos前节点指向新节点
    newNode->prev = posPrev;//新节点指回pos前节点

    newNode->next = pos;//新节点指向pos 
    pos->prev = newNode;//pos指回新节点
}

void DListPrint2(DLNode2* pHead)
{
    //用结构体指针 pHead 接收， 这里的 pHead 表示哨兵位。
    assert(pHead != NULL);
    DLNode2* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    if (cur == pHead)
    {
        printf("\n无借阅者。\n\n");
    }
    else
    {
        printf("\n<展示借阅者信息>\n");
    }
    while (cur != pHead)
    {
        printf("书号：%s\n", cur->data.book_number);
        printf("借阅者的书证号：%s\n", cur->data.borrower_number);
        printf("归还期限（年月日）：%s\n\n", cur->data.limit_date); // 可以用日期类，但不写了
        cur = cur->next;
    }
}

void ReturnBook(DLNode* pHead, DLNode2* pHead2)
{
    printf("\n<归还>\n");
    printf("请输入您的书证号\n");
    char borrower_number_tmp[20];
    scanf("%s", borrower_number_tmp);

    DLNode2* tmp2 = DListFind2(pHead2, borrower_number_tmp);
    if (tmp2 != NULL)
    {
        DLNode* tmp = DListFind(pHead, tmp2->data.book_number); // 通过书号找

        tmp->data.now_num += 1; // 还书，现存量+=1

        DListEarse2(tmp2); // 任意位置删借阅者，O（1），终于体现链表效率了

        printf("归还成功：\n");
    }
    else
    {
        printf("借阅者信息内无此书证号：\n");
    }
}

void DListEarse2(DLNode2* pos)
{
    assert(pos != NULL);
    assert(pos->next != pos);//防止删掉哨兵位头节点
    DLNode2* posPrev = pos->prev;
    DLNode2* posNext = pos->next;

    posPrev->next = posNext;//pos前节点指向pos后节点
    posNext->prev = posPrev;//pos后节点指回pos前节点
    free(pos);
    pos = NULL;//不置空也行
}

void DListDestory2(DLNode2* pHead)//保持接口函数的一致性就不传二级了，让使用者自己置空
{
    assert(pHead != NULL);
    DLNode2* cur = pHead->next;
    while (cur != pHead)
    {
        DLNode2* curNext = cur->next;
        free(cur);
        cur = curNext;
    }
    free(pHead);
    pHead = NULL;//不能使外面置空，让使用者自己置空
}

void SaveBorrower(DLNode2* pHead)
{
    assert(pHead != NULL);
    FILE* pf = fopen("Borrower.dat", "w");
    if (pf == NULL)
    {
        perror("SaveBorrower");
        return;
    }
    //写文件
    DLNode2* cur = pHead->next;
    //遍历链表就需要从 pHead->next 开始（即第一个有效数据节点）
    //当 cur 等于 pHead 就相当于全部走了一遍了，这时就结束。
    while (cur != pHead)
    {
        fwrite(&(cur->data), sizeof(Borrower), 1, pf);

        cur = cur->next;
    }
    fclose(pf);
    pf = NULL;
}